package fr.curriculumvitae.anthony.stephan.fragments;

import java.io.Serializable;
import java.lang.reflect.Field;

import fr.curriculumvitae.anthony.stephan.R;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class WhoAmIFragment extends Fragment implements Serializable {
	
	private static final String TAG = "WhoAmIFragment";
	private static final long serialVersionUID = -7335369050178792701L;
	
	private static final int FRAGMENT_CHANGE_DELAY_MILLIS 		= 3000; 	//ms
	private static final int FRAGMENT_CHANGE_INTERVAL_MILLIS 	= 200;		//ms
	
	private static Fragment INSTANCE = null;
	
	private static final int FIRST_DETAILS_PAGE 	= 0;
	private static final int DETAIL_ROW_1 			= 0;
	private static final int DETAIL_ROW_2 			= 1;
	private static final int DETAIL_ROW_3 			= 2;
	private static final int DETAIL_ROW_4 			= 3;
	
	private static final int[] TABLE_PAGES_1 = { 	R.layout.fragment_who_am_i_details_1_1,
													R.layout.fragment_who_am_i_details_2_1 };
	private static final int[] TABLE_PAGES_2 = { 	R.layout.fragment_who_am_i_details_1_2,
													R.layout.fragment_who_am_i_details_2_2 };
	private static final int[] TABLE_PAGES_3 = { 	R.layout.fragment_who_am_i_details_1_3,
													R.layout.fragment_who_am_i_details_2_3 };
	private static final int[] TABLE_PAGES_4 = { 	R.layout.fragment_who_am_i_details_1_4,
													R.layout.fragment_who_am_i_details_2_4 };
	private Handler handler;
	private boolean fragmentsAdded;
	
	private int current1;
	private int current2;
	private int current3;
	private int current4;
	
	private Fragment f1;
	private Fragment f2;
	private Fragment f3;
	private Fragment f4;
	
	private ChangeFragmentCallback callback1;
	private ChangeFragmentCallback callback2;
	private ChangeFragmentCallback callback3;
	private ChangeFragmentCallback callback4;
	
	public static Fragment getInstance() {
		if(INSTANCE == null) {
			INSTANCE = new WhoAmIFragment();
		} 
		return INSTANCE;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		Log.d(TAG, "onCreateView");
		ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_who_am_i, null);
		return root;
	}

	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		Log.d(TAG, "onViewCreated");
		if(!fragmentsAdded) {
			handler = new Handler();
			fragmentsAdded = false;
			callback1 = new ChangeFragmentCallback(DETAIL_ROW_1);
			callback2 = new ChangeFragmentCallback(DETAIL_ROW_2);
			callback3 = new ChangeFragmentCallback(DETAIL_ROW_3);
			callback4 = new ChangeFragmentCallback(DETAIL_ROW_4);
			current1 = FIRST_DETAILS_PAGE;
			current2 = FIRST_DETAILS_PAGE;
			current3 = FIRST_DETAILS_PAGE;
			current4 = FIRST_DETAILS_PAGE;
			fetchViews();
			addFragments();
			launchCallbacks();
		}
	}
	
	@Override 
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if(fragmentsAdded) {
			removeCallbacks();
		}
	}
	
	@Override
	public void onPause() {
		super.onPause();
		if(fragmentsAdded) {
			removeCallbacks();
		}
	}
	
	@Override
	public void onStop() {
		super.onStop();		
		if(fragmentsAdded) {
			removeCallbacks();
		}
	}
	
	@Override 
	public void onResume() {
		super.onResume();
		launchCallbacks();
		fragmentsAdded = true;
	}
	
	@Override 
	public void onDetach() {
		super.onDetach();
		if(fragmentsAdded) {
			removeCallbacks();
		}
        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        fragmentsAdded = false;
	}
	
	@Override 
	public void onDestroy() {
		super.onDestroy();
		removeCallbacks();
		fragmentsAdded = false;
	}
	
	private void fetchViews() {
		/* nothing to do */
	}

	private void addFragments() {
		f1 = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_1[current1]);
		f2 = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_2[current2]);
		f3 = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_3[current3]);
		f4 = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_4[current4]);
		Log.d(TAG, "addFragment");
        getChildFragmentManager()
        	.beginTransaction()
        	.add(R.id.frameLayout_host_1, f1)
        	.add(R.id.frameLayout_host_2, f2)
        	.add(R.id.frameLayout_host_3, f3)
        	.add(R.id.frameLayout_host_4, f4)
        	.addToBackStack(null)
        	.commit();
        Log.d(TAG, "fragmentsAdded");
        fragmentsAdded = true;
	}
	
	@SuppressWarnings("unused")
	private void removeFragments() {
        getChildFragmentManager()
        	.beginTransaction()
        	.remove(f1)
        	.remove(f2)
        	.remove(f3)
        	.remove(f4)
        	.commit();
        fragmentsAdded = false;
	}
	
	private void launchCallbacks() {
		handler.postDelayed(callback1, FRAGMENT_CHANGE_DELAY_MILLIS+0*FRAGMENT_CHANGE_INTERVAL_MILLIS);
		handler.postDelayed(callback2, FRAGMENT_CHANGE_DELAY_MILLIS+1*FRAGMENT_CHANGE_INTERVAL_MILLIS);
		handler.postDelayed(callback3, FRAGMENT_CHANGE_DELAY_MILLIS+2*FRAGMENT_CHANGE_INTERVAL_MILLIS);
		handler.postDelayed(callback4, FRAGMENT_CHANGE_DELAY_MILLIS+3*FRAGMENT_CHANGE_INTERVAL_MILLIS);
	}
	
	private void removeCallbacks() {
		handler.removeCallbacks(callback1);
		handler.removeCallbacks(callback2);
		handler.removeCallbacks(callback3);
		handler.removeCallbacks(callback4);
	}
	
	private void changeFragment(int id) {
		Fragment f = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_1[current1]);
		int fragmentID = R.id.frameLayout_host_1;
		switch(id) {
		case DETAIL_ROW_1:
			current1++;
			if(current1 >= TABLE_PAGES_1.length) {
				current1 = FIRST_DETAILS_PAGE;
			}
			f = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_1[current1]);
			f1 = f;
			fragmentID = R.id.frameLayout_host_1;
			break;
		case DETAIL_ROW_2:
			current2++;
			if(current2 >= TABLE_PAGES_2.length) {
				current2 = FIRST_DETAILS_PAGE;
			}
			f = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_2[current2]);
			f2 = f;
			fragmentID = R.id.frameLayout_host_2;
			break;
		case DETAIL_ROW_3:
			current3++;
			if(current3 >= TABLE_PAGES_3.length) {
				current3 = FIRST_DETAILS_PAGE;
			}
			f = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_3[current3]);
			f3 = f;
			fragmentID = R.id.frameLayout_host_3;
			break;
		case DETAIL_ROW_4:
			current4++;
			if(current4 >= TABLE_PAGES_4.length) {
				current4 = FIRST_DETAILS_PAGE;
			}
			f = WhoAmIDetailsFragment.newInstance(TABLE_PAGES_4[current4]);
			f4 = f;
			fragmentID = R.id.frameLayout_host_4;
			break;
		}
		getChildFragmentManager()
			.beginTransaction()
			.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
			.replace(fragmentID, f)
			.addToBackStack(null)
			.commit();
	}
	
	
	  ///////////////
	 // CALLBACKS //
	///////////////
	
	private class ChangeFragmentCallback implements Runnable, Serializable {

		private static final long serialVersionUID = -9147887111750653355L;
		
		private int id;
		public ChangeFragmentCallback(int id) {
			this.id = id;
		}
		@Override
		public void run() {
			changeFragment(id);
			switch(id) {
			case DETAIL_ROW_1:
				handler.removeCallbacks(callback1);
				break;
			case DETAIL_ROW_2:
				handler.removeCallbacks(callback2);
				break;
			case DETAIL_ROW_3:
				handler.removeCallbacks(callback3);
				break;
			case DETAIL_ROW_4:
				handler.removeCallbacks(callback4);
				launchCallbacks();
				break;
			}
		}
	};

}
